﻿Imports System.Data.Common
Imports Microsoft.Practices.EnterpriseLibrary.Data
Imports Microsoft.Practices.EnterpriseLibrary.Common.Configuration
Imports System.IO
Imports System.Data
Imports Peer.PublicVBModule.VBReflection
Imports Peer.PublicVBModule.VBXml
Imports FY.YinXinSDK
Imports System.Diagnostics
Imports log4net
Imports TjLog
Public Class ReflectStruct
    Public Shared ReflectHelperIns As ReflectHelper = New ReflectHelper
    Private Shared lockobj As Object = New Object()
    '销毁指定编码下指定关键字的内存缓存及配置结构
    Public Shared Sub ClearOneReflectInfo(ByVal Plat_Code As String, ByVal keyinfo As String)
        '获取当前关键字DLL的命名空间和类名
        Dim setNodeIns As Peer.PublicVBModule.VBReflection.ReflectSetNode = ReflectHelperIns.GetReflectSetDic(Plat_Code)(keyinfo)
        Dim key As String = setNodeIns.CurNameSpace + "." + setNodeIns.CurClassName
        ReflectHelperIns.GetOrgService(Plat_Code).dic.Remove(key)
        ReflectHelperIns.GetOrgService(Plat_Code).VBAssembly = Nothing
        ReflectHelperIns.GetReflectSetDic(Plat_Code).Remove(keyinfo)
    End Sub
    '销毁指定编码下全部关键字的内存缓存及配置结构
    Public Shared Sub ClearAllReflectInfo(ByVal Plat_Code As String)
        ReflectHelperIns.GetOrgService(Plat_Code).dic.Clear()
        ReflectHelperIns.GetOrgService(Plat_Code).VBAssembly = Nothing
        ReflectHelperIns.GetReflectSetDic(Plat_Code).Clear()
    End Sub
    Public Shared Sub ReadReflectDll(ByVal Plat_Code As String)
        Dim ServerPath As String = AppDomain.CurrentDomain.BaseDirectory
        Dim DllSetPath As String = ServerPath + Plat_Code
        Dim yixin_db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)("fyyixin")

        If Directory.Exists(DllSetPath) = True Then
            Try
                '读取配置表
                Dim dt As DataTable = yixin_db.ExecuteDataSet(CommandType.Text, "select plat_code,keyinfo,namespace,classname,dllpath,methodname from t_servicelogic_info where stop_flag=0 and plat_code='" + Plat_Code + "'").Tables(0)
                Dim i As Integer = 0
                If IsNothing(dt) = False AndAlso dt.Rows.Count > 0 Then
                    '读取之前先保证清空已经存在的逻辑；便于保证逻辑始终最新（要更新就更新此平台全部逻辑）
                    ClearAllReflectInfo(Plat_Code)
                    For i = 0 To dt.Rows.Count - 1
                        Dim setNodeIns As Peer.PublicVBModule.VBReflection.ReflectSetNode = New Peer.PublicVBModule.VBReflection.ReflectSetNode()
                        setNodeIns.CurKeyinfo = dt.Rows(i)("keyinfo").ToString()
                        '配置文件中的CurOrgCode节点非常重要，必须等于Plat_Code
                        setNodeIns.CurOrgCode = dt.Rows(i)("plat_code").ToString()
                        setNodeIns.CurNameSpace = dt.Rows(i)("namespace").ToString()
                        setNodeIns.CurClassName = dt.Rows(i)("classname").ToString()
                        setNodeIns.CurDllPath = ServerPath + Plat_Code + "\" + dt.Rows(i)("dllpath").ToString()
                        setNodeIns.CurMethodName = dt.Rows(i)("methodname").ToString()
                        ReflectHelperIns.GetReflectSetDic(setNodeIns.CurOrgCode).Add(setNodeIns.CurKeyinfo, setNodeIns)
                        '根据配置文件读取外部处理逻辑到内存
                        ReflectHelperIns.AddDllToMemory(setNodeIns.CurOrgCode, setNodeIns.CurDllPath, setNodeIns.CurNameSpace, setNodeIns.CurClassName, setNodeIns.CurMethodName)
                        TjLog.Log.InfoLog("消息接收服务读取dll到内存成功：" + setNodeIns.CurClassName, Plat_Code, "21", "反射导入客服消息业务逻辑DLL到内存", "PreMsgWarm")
                        TjLog.Log.FileLog.Info("消息接收服务读取dll到内存成功：" + setNodeIns.CurClassName)
                    Next
                    dt.Clear()
                    dt = Nothing
                    TjLog.Log.InfoLog("消息接收服务读取所有dll到内存操作成功！", Plat_Code, "21", "反射导入客服消息业务逻辑DLL到内存", "PreMsgWarm")
                    TjLog.Log.FileLog.Info("消息接收服务读取所有dll到内存操作成功！")
                End If
            Catch ex As Exception
                Dim ErrorStr As String = TjLog.Log.getLogInfo(New StackFrame(True))
                TjLog.Log.ErrorLog("消息接收服务读取所有dll到内存操作异常：" + ex.ToString() + ErrorStr, Plat_Code, "22", "", "PreWarm")
                TjLog.Log.FileLog.Error("消息接收服务读取所有dll到内存操作异常：" + ex.ToString + ErrorStr)
            End Try

        Else
            TjLog.Log.ErrorLog("读取【" + Plat_Code + "】编号的消息接收服务配置文件异常，业务逻辑目录不存在：" + DllSetPath, Plat_Code, "16", "读取客服消息业务逻辑配置文件异常", "ReadMsgDllSetFile")
            TjLog.Log.FileLog.Error("读取【" + Plat_Code + "】编号的消息接收服务配置文件异常，业务逻辑目录不存在：" + DllSetPath)
        End If

    End Sub

    '读取当前关键字的业务逻辑到内存
    Public Shared Sub ReadReflectDll(ByVal Plat_Code As String, ByVal keyinfo As String)
        Dim ServerPath As String = AppDomain.CurrentDomain.BaseDirectory
        Dim DllSetPath As String = ServerPath + Plat_Code
        Dim yixin_db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)("fyyixin")

        If Directory.Exists(DllSetPath) = True Then
            Try
                '读取配置表
                Dim dt As DataTable = yixin_db.ExecuteDataSet(CommandType.Text, "select plat_code,keyinfo,namespace,classname,dllpath,methodname from t_servicelogic_info where  plat_code='" + Plat_Code + "' and keyinfo='" + keyinfo + "'").Tables(0)
                Dim i As Integer = 0
                If IsNothing(dt) = False AndAlso dt.Rows.Count > 0 Then
                    '读取之前先保证清空已经存在的逻辑；便于保证逻辑始终最新
                    If ReflectStruct.ReflectHelperIns.GetReflectSetDic(Plat_Code).ContainsKey(keyinfo) = True Then
                        '移除此业务逻辑
                        ClearOneReflectInfo(Plat_Code, keyinfo)
                    End If
                    For i = 0 To dt.Rows.Count - 1
                        Dim setNodeIns As Peer.PublicVBModule.VBReflection.ReflectSetNode = New Peer.PublicVBModule.VBReflection.ReflectSetNode()
                        setNodeIns.CurKeyinfo = dt.Rows(i)("keyinfo").ToString()
                        '配置文件中的CurOrgCode节点非常重要，必须等于Plat_Code
                        setNodeIns.CurOrgCode = dt.Rows(i)("plat_code").ToString()
                        setNodeIns.CurNameSpace = dt.Rows(i)("namespace").ToString()
                        setNodeIns.CurClassName = dt.Rows(i)("classname").ToString()
                        setNodeIns.CurDllPath = ServerPath + Plat_Code + "\" + dt.Rows(i)("dllpath").ToString()
                        setNodeIns.CurMethodName = dt.Rows(i)("methodname").ToString()
                        ReflectHelperIns.GetReflectSetDic(setNodeIns.CurOrgCode).Add(setNodeIns.CurKeyinfo, setNodeIns)
                        '根据配置文件读取外部处理逻辑到内存
                        ReflectHelperIns.AddDllToMemory(setNodeIns.CurOrgCode, setNodeIns.CurDllPath, setNodeIns.CurNameSpace, setNodeIns.CurClassName, setNodeIns.CurMethodName)
                        TjLog.Log.InfoLog("消息接收服务读取dll到内存成功：" + setNodeIns.CurClassName, Plat_Code, "21", "反射导入客服消息业务逻辑DLL到内存", "PreMsgWarm")
                        TjLog.Log.FileLog.Info("消息接收服务读取dll到内存成功：" + setNodeIns.CurClassName)
                    Next
                    dt.Clear()
                    dt = Nothing
                End If
            Catch ex As Exception
                Dim ErrorStr As String = TjLog.Log.getLogInfo(New StackFrame(True))
                TjLog.Log.ErrorLog("消息接收服务读取所有dll到内存操作异常：" + ex.ToString() + ErrorStr, Plat_Code, "22", "", "PreWarm")
                TjLog.Log.FileLog.Error("消息接收服务读取所有dll到内存操作异常：" + ex.ToString() + ErrorStr)
            End Try

        Else
            TjLog.Log.ErrorLog("读取【" + Plat_Code + "】编号的消息接收服务配置文件异常，业务逻辑目录不存在：" + DllSetPath, Plat_Code, "16", "读取客服消息业务逻辑配置文件异常", "ReadMsgDllSetFile")
            TjLog.Log.FileLog.Error("读取【" + Plat_Code + "】编号的消息接收服务配置文件异常，业务逻辑目录不存在：" + DllSetPath)
        End If
    End Sub

    Public Shared Sub ReadConfigDLL(plat_code As String)
        Dim yixin_db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)("fyyixin")

        SyncLock lockobj
            Dim dt As DataTable = yixin_db.ExecuteDataSet(CommandType.Text, "select plat_type,plat_code,appid,appsecret,token,update_flag from t_plat_info where active_flag=1 and plat_code='" + plat_code + "'").Tables(0)

            If dt IsNot Nothing AndAlso dt.Rows.Count = 1 Then
                Dim curtype As Integer = Convert.ToInt32(dt.Rows(0)("plat_type"))
                Dim update_flag As Integer = Convert.ToInt32(dt.Rows(0)("update_flag"))
                Dim appid As String = If(dt.Rows(0)("appid").ToString(), "")
                Dim appsecret As String = If(dt.Rows(0)("appsecret").ToString(), "")
                Dim token As String = dt.Rows(0)("token").ToString()
               
                dt.Clear()
                If Not YinXin.getTokenState(plat_code) OrElse update_flag = 1 Then
                    If Not YinXin.getTokenState(plat_code) Then
                        TjLog.Log.InfoLog("SDK不存在此编码！", plat_code, "17", "需要更新配置", "UpdatePlatInfo")
                        TjLog.Log.FileLog.Info(plat_code + "平台需要更新配置！")
                    End If
                    AddYinXinPlatConfig(plat_code, curtype, token, appid, appsecret)
                    ReflectStruct.ReadReflectDll(plat_code)
                End If
                If update_flag = 1 Then
                    yixin_db.ExecuteNonQuery(CommandType.Text, "update t_plat_info set update_flag=0 where plat_code='" + plat_code + "'")
                End If
            Else
                Log.ErrorLog("此平台没有激活，请登录微信公众平台服务框架配置管理系统对【" + plat_code + "】进行激活后才可以使用此服务！", plat_code, "-2-2", "回复消息给用户", "reply")
                Log.FileLog.Error("此平台没有激活，请登录微信公众平台服务框架配置管理系统对【" + plat_code + "】进行激活后才可以使用此服务！")
            End If

        End SyncLock
    End Sub
    Public Shared Sub YinXinCache()
        '只查询已经激活的
        Dim sqlstr As String = "select plat_type,plat_code,appid,appsecret,token from t_plat_info where active_flag=1"
        Dim yixin_db As Database = EnterpriseLibraryContainer.Current.GetInstance(Of Database)("fyyixin")
        Dim dt As DataTable = yixin_db.ExecuteDataSet(CommandType.Text, sqlstr).Tables(0)
        If (IsNothing(dt) = False AndAlso dt.Rows.Count > 0) Then
            For i As Integer = 0 To dt.Rows.Count - 1
                Dim curtype As Integer = Convert.ToInt32(dt.Rows(i)("plat_type"))
                Dim plat_code As String = dt.Rows(i)("plat_code").ToString()
                Dim appid As String = IIf(IsNothing(dt.Rows(i)("appid").ToString()), "", dt.Rows(i)("appid").ToString())
                Dim appsecret As String = IIf(IsNothing(dt.Rows(i)("appsecret").ToString()), "", dt.Rows(i)("appsecret").ToString())
                Dim token As String = dt.Rows(i)("token").ToString()
                '加载该平台配置信息到sdk
                AddYinXinPlatConfig(plat_code, curtype, token, appid, appsecret)
            Next i
            dt.Clear()
            dt = Nothing
        End If
    End Sub
    '微信缓存
    Private Shared Sub AddYinXinPlatConfig(ByVal plat_code As String, ByVal curtype As Integer, ByVal token As String, ByVal appid As String, ByVal appsecret As String)

        YinXin.SetToken(plat_code, token)
        '已经认证的服务号订阅号(微信公众号类型：0订阅号 1已经认证订阅号  2已认证服务号)
        If curtype <> 0 Then
            '设置全局配置
            YinXin.ConfigGlobalCredential(plat_code, appid, appsecret)
            '设置AccessToken缓存存取方案
            YinXin.ConfigAccessTokenCache(plat_code, Sub(credential As ClientCredential)
                                                         HttpRuntime.Cache.Add(plat_code, credential.access_token, Nothing, DateTime.Now.AddSeconds(CDec((credential.expires_in - 30))), Cache.NoSlidingExpiration, CacheItemPriority.Default, Nothing)
                                                     End Sub, Function() TryCast(HttpRuntime.Cache.[Get](plat_code), String))
        End If
    End Sub
End Class

